# 生成数据
import numpy as np
from sklearn.linear_model import LinearRegression

# 生成随机数
np.random.seed(1234)
x = np.random.rand(500, 3)
print(x.shape)
# print(x)

# 构建映射关系，模拟真实的数据待预测值,映射关系为y = 4.2 + 5.7*x1 + 10.8*x2，可自行设置值进行尝试
y = x.dot(np.array([4.2, 5.7, 10.8]))  # 矩阵相乘 x.dot(y) 等价于 np.dot(x,y)
print(y.shape)


# print(y)


# np.array([4.2,5.7,10.8])      （3，）既不是行向量也不是列向量，只是有3个元素，是一个维度为3的数组
def lineRegression():
    # 调用模型
    lr = LinearRegression(fit_intercept=True)
    # 训练模型
    lr.fit(x, y)
    print("估计的参数值为：%s" % (lr.coef_))
    # 计算R平方
    print('R2:%s' % (lr.score(x, y)))
    # 任意设定变量，预测目标值
    x_test = np.array([2, 4, 5]).reshape(1, -1)  # 定义一个行向量
    y_hat = lr.predict(x_test)
    print("预测值为: %s" % y_hat)


class LR_LS():
    def __init__(self):
        self.w = None

    def fit(self, X, y):
        # 最小二乘法矩阵求解
        # ============================= show me your code =======================
        # self.w = np.lineal.inv(X).dot(y)
        self.w = np.linalg.inv(X.T.dot(X)).dot(X.T).dot(y)
        # ============================= show me your code =======================

    def predict(self, X):
        # 用已经拟合的参数值预测新自变量
        # ============================= show me your code =======================
        y_pred = X.dot(self.w)
        # ============================= show me your code =======================
        return y_pred


class LR_GD():
    def __init__(self):
        self.w = None

    def fit(self, X, y, alpha=0.02, loss=1e-10):  # 设定步长为0.002,判断是否收敛的条件为1e-10
        y = y.reshape(-1, 1)  # 重塑y值的维度以便矩阵运算
        [m, d] = np.shape(X)  # 自变量的维度
        self.w = np.zeros(d)  # 将参数的初始值定为0
        tol = 1e5
        # ============================= show me your code =======================
        while tol > loss:
            h_f = X.dot(self.w).reshape(-1, 1)
            theta = self.w + alpha * np.mean(X * (y - h_f), axis=0)  # 计算迭代的参数值
            tol = np.sum(np.abs(theta - self.w))
            self.w = theta
        # ============================= show me your code =======================

    def predict(self, X):
        # 用已经拟合的参数值预测新自变量
        y_pred = X.dot(self.w)
        return y_pred


if __name__ == "__main__":
    lr_gd = LR_GD()
    lr_gd.fit(x, y)
    print("估计的参数值为：%s" % lr_gd.w)
    x_test = np.array([2, 4, 5]).reshape(1, -1)
    print("预测值为：%s" % (lr_gd.predict(x_test)))

# if __name__ == "__main__":
#     lr_ls = LR_LS()
#     lr_ls.fit(x, y)
#     print("估计的参数值：%s" % lr_ls.w)
#     x_test = np.array([2, 4, 5]).reshape(1, -1)
#     print("预测值为: %s" % (lr_ls.predict(x_test)))
